package edu.bath.sensorframework.triplestore.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.StackPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class SensorTripleStore implements EntryPoint {
	private TripeStoreAgentServiceAsync service = TripeStoreAgentService.Util.getInstance();
	
	private boolean passwordChanged = false;
	
	private TextBox serverURL = new TextBox();
	private TextBox username = new TextBox();
	private PasswordTextBox password = new PasswordTextBox();
	private TextBox catID = new TextBox();
	private TextBox repoID = new TextBox();
	private boolean serverSettingsEnabled = true;
	
	private void disableServerSettings() {
		this.serverSettingsEnabled = false;
		
		serverURL.setEnabled(false);
		username.setEnabled(false);
		password.setEnabled(false);
		catID.setEnabled(false);
		repoID.setEnabled(false);
	}
	
	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		RootPanel rootPanel = RootPanel.get("contentContainer");
		VerticalPanel outerPanel = new VerticalPanel();
		outerPanel.setWidth("100%");
		rootPanel.add(outerPanel);
		
		// AllegroGraph settings
		VerticalPanel agraphSettingsPanel = new VerticalPanel();
		Label agraphSettingsLabel = new Label("These are the settings for the AllegroGraph " +
				"triple store used as the backend for the sensor framework.");
		agraphSettingsPanel.add(agraphSettingsLabel);
		
		final Label successfulSaveLabel = new Label("Settings successfully updated");
		successfulSaveLabel.setVisible(false);
		
		FlexTable t = new FlexTable();
		agraphSettingsPanel.add(t);

		t.setWidget(0, 0, new Label("Server URL"));
		t.setWidget(0, 1, serverURL);
		serverURL.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				successfulSaveLabel.setVisible(false);
			}
		});
		
		t.setWidget(1, 0, new Label("Username"));
		t.setWidget(1, 1, username);
		username.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				successfulSaveLabel.setVisible(false);
			}
		});
		
		t.setWidget(2, 0, new Label("Password"));
		t.setWidget(2, 1, password);
		password.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				successfulSaveLabel.setVisible(false);
				passwordChanged = true;
			}
		});
		
		t.setWidget(0, 20, new Label("Catalogue ID"));
		t.setWidget(0, 21, catID);
		catID.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				successfulSaveLabel.setVisible(false);
			}
		});
		
		t.setWidget(1, 20, new Label("Repo ID"));
		t.setWidget(1, 21, repoID);
		repoID.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				successfulSaveLabel.setVisible(false);
			}
		});
		
		// TODO: Make this atomic i.e. they all save or none of them do
		final AsyncCallback<Void> saveCallback = new AsyncCallback<Void>() {
			public void onFailure(Throwable caught) {
				Window.alert("Failed to save settings, try again.");
			}
			public void onSuccess(Void result) {successfulSaveLabel.setVisible(true);}
		};
		Button saveSettingsButton = new Button("Save", new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if(!serverSettingsEnabled) {
					Window.alert("Error contacting server, could not retrieve all server settings.");
					return;
				} else {
					successfulSaveLabel.setVisible(false);
					if(passwordChanged)
						service.updateSettings(serverURL.getText(), 
								username.getText(), password.getText(), 
								catID.getText(), repoID.getText(), saveCallback);
					else
						service.updateSettings(serverURL.getText(), 
								username.getText(), catID.getText(), 
								repoID.getText(), saveCallback);
				}
			}
		});
		agraphSettingsPanel.add(saveSettingsButton);
		agraphSettingsPanel.add(successfulSaveLabel);
		
		// Populate form
		populateSettings();
		
		// Data sources panel
		HTML space = new HTML("&#160;");
		VerticalPanel dataSourcesPanel = new VerticalPanel();
		dataSourcesPanel.setWidth("100%");
		dataSourcesPanel.add(new Label("Manage the data sources tracked by the system here."));
		HorizontalPanel dataSourcesButtons = new HorizontalPanel();
		dataSourcesButtons.setWidth("100%");
		dataSourcesPanel.add(dataSourcesButtons);
		
		HorizontalPanel addAndSavePanel = new HorizontalPanel();
		dataSourcesButtons.add(addAndSavePanel);
		final Button addSourceButton = new Button("Add");
		addSourceButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				final PopupPanel panel = new PopupPanel();
				panel.setGlassEnabled(true);
				HorizontalPanel hp = new HorizontalPanel();
				panel.setWidget(hp);
				panel.showRelativeTo(addSourceButton);
				
				hp.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
				hp.add(new HTML("<b>Handle:</b> "));
				
				final TextBox handle = new TextBox();
				handle.setVisibleLength(15);
				hp.add(handle);
				
				hp.add(new HTML("&#160;"));
				
				Button add = new Button("Add", new ClickHandler() {
					public void onClick(ClickEvent event) {
						service.addDataSource(handle.getText(), new AsyncCallback<Void>() {
							@Override
							public void onFailure(Throwable caught) {
								Window.alert("Couldn't add data source! "+caught.getMessage());
								panel.hide();
							}

							@Override
							public void onSuccess(Void result) {
								Window.alert("Success!"); // TODO: Add to the list of data sources
							}
						});
					}
				});
				hp.add(add);
				
				hp.add(new HTML("&#160;"));
				hp.add(new Button("Cancel", new ClickHandler() {
					@Override
					public void onClick(ClickEvent event) {
						panel.hide();
					}
				}));
			}
		});
		addAndSavePanel.add(addSourceButton);
		addAndSavePanel.add(space);
		
		Button saveConfigButton = new Button("Save Config");
		addAndSavePanel.add(saveConfigButton);
		
		dataSourcesButtons.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		Button clearSourceButton = new Button("Clear");
		dataSourcesButtons.add(clearSourceButton);
		
		// Stack panel for different settings
		StackPanel panel = new StackPanel();
		panel.setWidth("100%");
		outerPanel.add(panel);
		panel.add(dataSourcesPanel, "Data Sources");
		panel.add(agraphSettingsPanel, "AllegroGraph Settings");
		panel.add(new Label("asdad"), "Virtual Sensors");
		panel.add(new Label("asdasd"), "Help");
	}
	
	/**
	 * Loads the AllegroGraph settings from the server and populates the form.
	 */
	private void populateSettings() {
		AsyncCallback<String> usernameCallback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				disableServerSettings();
			}

			@Override
			public void onSuccess(String result) {
				username.setText(result);
			}
		};
		service.getAgraphUsername(usernameCallback);
		
		AsyncCallback<String> serverURLCallback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				disableServerSettings();
			}

			@Override
			public void onSuccess(String result) {
				serverURL.setText(result);
			}
		};
		service.getAgraphServerURL(serverURLCallback);
		
		AsyncCallback<String> catIDCallback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				disableServerSettings();
			}

			@Override
			public void onSuccess(String result) {
				catID.setText(result);
			}
		};
		service.getAgraphCatID(catIDCallback);
		
		AsyncCallback<String> repoIDCallback = new AsyncCallback<String>() {
			@Override
			public void onFailure(Throwable caught) {
				disableServerSettings();
			}

			@Override
			public void onSuccess(String result) {
				repoID.setText(result);
			}
		};
		service.getAgraphRepoID(repoIDCallback);
		
		AsyncCallback<Boolean> passwordCallback = new AsyncCallback<Boolean>() {
			@Override
			public void onFailure(Throwable caught) {
				disableServerSettings();
			}

			@Override
			public void onSuccess(Boolean result) {
				if(result.booleanValue())
					password.setText("**********");
				else
					password.setText("");
			}
		};
		service.hasAgraphPassword(passwordCallback);
	}
}
